package com.gitee.ly.ymorm.log;

import com.gitee.ly.ymorm.exceptions.YmOrmException;
import com.gitee.ly.ymorm.log.nologger.NoLoggerImpl;
import com.gitee.ly.ymorm.log.slf4j.Slf4jImpl;

import java.lang.reflect.Constructor;
import java.util.concurrent.locks.ReentrantLock;

/**
 * LogFactory
 *
 * @author ly
 **/
public final class YmOrmLogFactory {
    private static final ReentrantLock lock = new ReentrantLock();
    private static Constructor<? extends YmOrmLog> logConstructor;

    static {
        tryImplementation(YmOrmLogFactory::useSlf4jLogging);
        tryImplementation(YmOrmLogFactory::useNoLogging);
    }

    private YmOrmLogFactory() {
    }

    public static YmOrmLog getLog(Class<?> clazz) {
        return getLog(clazz.getName());
    }

    public static YmOrmLog getLog(String logger) {
        try {
            return logConstructor.newInstance(logger);
        } catch (Throwable t) {
            throw new YmOrmException("Error creating logger for logger " + logger + ".  Cause: " + t, t);
        }
    }

    public static void useCustomLogging(Class<? extends YmOrmLog> clazz) {
        setImplementation(clazz);
    }

    public static void useSlf4jLogging() {
        setImplementation(Slf4jImpl.class);
    }

    public static void useNoLogging() {
        setImplementation(NoLoggerImpl.class);
    }

    private static void tryImplementation(Runnable runnable) {
        if (logConstructor == null) {
            try {
                runnable.run();
            } catch (Throwable t) {
                // ignore
            }
        }
    }

    private static void setImplementation(Class<? extends YmOrmLog> implClass) {
        lock.lock();
        try {
            Constructor<? extends YmOrmLog> candidate = implClass.getConstructor(String.class);
            YmOrmLog log = candidate.newInstance(YmOrmLogFactory.class.getName());
            log.debug("YmOrmLog initialized using '" + implClass + "' adapter.");
            logConstructor = candidate;
        } catch (Throwable t) {
            throw new YmOrmException("Error setting Log implementation.  Cause: " + t, t);
        } finally {
            lock.unlock();
        }
    }

}
